package snapshot

import (
	"fmt"
	"time"

	log "github.com/sirupsen/logrus"
	"libvirt.org/go/libvirt"
)

// Service 快照管理服务
type Service struct {
	connManager ConnManager
}

// ConnManager 连接管理器接口
type ConnManager interface {
	WithConn(fn func(*libvirt.Connect) error) error
}

// NewService 创建快照服务
func NewService(cm ConnManager) *Service {
	return &Service{connManager: cm}
}

// SnapshotInfo 快照信息
type SnapshotInfo struct {
	Name         string    `json:"name"`
	Domain       string    `json:"domain"`
	CreationTime time.Time `json:"creation_time"`
	State        string    `json:"state"`
	Description  string    `json:"description,omitempty"`
	Parent       string    `json:"parent,omitempty"`
	IsCurrent    bool      `json:"is_current"`
	XMLConfig    string    `json:"xml_config,omitempty"`
}

// CreateSpec 创建快照的规格
type CreateSpec struct {
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	MemoryState bool   `json:"memory_state"` // 是否包含内存状态
	DiskOnly    bool   `json:"disk_only"`    // 仅磁盘快照
	Quiesce     bool   `json:"quiesce"`      // 使用 guest agent 静默文件系统
	Atomic      bool   `json:"atomic"`       // 原子操作
}

// Create 创建快照
func (s *Service) Create(domainName string, spec *CreateSpec) (*SnapshotInfo, error) {
	var snapInfo *SnapshotInfo

	err := s.connManager.WithConn(func(conn *libvirt.Connect) error {
		dom, err := conn.LookupDomainByName(domainName)
		if err != nil {
			return fmt.Errorf("domain not found: %w", err)
		}
		defer dom.Free()

		// 构建快照 XML
		snapXML := s.buildSnapshotXML(spec)

		// 设置快照创建标志
		flags := libvirt.DomainSnapshotCreateFlags(0)
		if spec.MemoryState {
			// 包含内存状态（仅当 VM 运行时）
			state, _, err := dom.GetState()
			if err == nil && state == libvirt.DOMAIN_RUNNING {
				// 默认行为已包含内存
			}
		}
		if spec.DiskOnly {
			flags |= libvirt.DOMAIN_SNAPSHOT_CREATE_DISK_ONLY
		}
		if spec.Quiesce {
			flags |= libvirt.DOMAIN_SNAPSHOT_CREATE_QUIESCE
		}
		if spec.Atomic {
			flags |= libvirt.DOMAIN_SNAPSHOT_CREATE_ATOMIC
		}

		log.Infof("Creating snapshot for domain %s with flags %d", domainName, flags)

		// 创建快照
		snap, err := dom.CreateSnapshotXML(snapXML, flags)
		if err != nil {
			return fmt.Errorf("failed to create snapshot: %w", err)
		}
		defer snap.Free()

		snapInfo, err = s.getSnapshotInfo(dom, snap, false)
		if err != nil {
			return fmt.Errorf("failed to get snapshot info: %w", err)
		}

		log.Infof("Snapshot %s created successfully for domain %s", snapInfo.Name, domainName)
		return nil
	})

	return snapInfo, err
}

// List 列出域的所有快照
func (s *Service) List(domainName string) ([]SnapshotInfo, error) {
	var snapshots []SnapshotInfo

	err := s.connManager.WithConn(func(conn *libvirt.Connect) error {
		dom, err := conn.LookupDomainByName(domainName)
		if err != nil {
			return fmt.Errorf("domain not found: %w", err)
		}
		defer dom.Free()

		snaps, err := dom.ListAllSnapshots(0)
		if err != nil {
			return fmt.Errorf("failed to list snapshots: %w", err)
		}

		for _, snap := range snaps {
			info, err := s.getSnapshotInfo(dom, &snap, false)
			if err != nil {
				log.Warnf("Failed to get snapshot info: %v", err)
				continue
			}
			snapshots = append(snapshots, *info)
			snap.Free()
		}

		return nil
	})

	return snapshots, err
}

// Get 获取特定快照信息
func (s *Service) Get(domainName, snapshotName string, includeXML bool) (*SnapshotInfo, error) {
	var snapInfo *SnapshotInfo

	err := s.connManager.WithConn(func(conn *libvirt.Connect) error {
		dom, err := conn.LookupDomainByName(domainName)
		if err != nil {
			return fmt.Errorf("domain not found: %w", err)
		}
		defer dom.Free()

		snap, err := dom.SnapshotLookupByName(snapshotName, 0)
		if err != nil {
			return fmt.Errorf("snapshot not found: %w", err)
		}
		defer snap.Free()

		snapInfo, err = s.getSnapshotInfo(dom, snap, includeXML)
		return err
	})

	return snapInfo, err
}

// Revert 回滚到指定快照
func (s *Service) Revert(domainName, snapshotName string, force bool) error {
	return s.connManager.WithConn(func(conn *libvirt.Connect) error {
		dom, err := conn.LookupDomainByName(domainName)
		if err != nil {
			return fmt.Errorf("domain not found: %w", err)
		}
		defer dom.Free()

		snap, err := dom.SnapshotLookupByName(snapshotName, 0)
		if err != nil {
			return fmt.Errorf("snapshot not found: %w", err)
		}
		defer snap.Free()

		flags := libvirt.DomainSnapshotRevertFlags(0)
		if force {
			flags |= libvirt.DOMAIN_SNAPSHOT_REVERT_FORCE
		}

		log.Infof("Reverting domain %s to snapshot %s", domainName, snapshotName)

		// 使用快照对象的RevertToSnapshot方法
		if err := snap.RevertToSnapshot(flags); err != nil {
			return fmt.Errorf("failed to revert to snapshot: %w", err)
		}

		log.Infof("Domain %s reverted to snapshot %s", domainName, snapshotName)
		return nil
	})
}

// Delete 删除快照
func (s *Service) Delete(domainName, snapshotName string, deleteChildren bool) error {
	return s.connManager.WithConn(func(conn *libvirt.Connect) error {
		dom, err := conn.LookupDomainByName(domainName)
		if err != nil {
			return fmt.Errorf("domain not found: %w", err)
		}
		defer dom.Free()

		snap, err := dom.SnapshotLookupByName(snapshotName, 0)
		if err != nil {
			return fmt.Errorf("snapshot not found: %w", err)
		}
		defer snap.Free()

		flags := libvirt.DomainSnapshotDeleteFlags(0)
		if deleteChildren {
			flags |= libvirt.DOMAIN_SNAPSHOT_DELETE_CHILDREN
		}

		log.Infof("Deleting snapshot %s from domain %s", snapshotName, domainName)

		if err := snap.Delete(flags); err != nil {
			return fmt.Errorf("failed to delete snapshot: %w", err)
		}

		log.Infof("Snapshot %s deleted from domain %s", snapshotName, domainName)
		return nil
	})
}

// GetCurrent 获取当前快照
func (s *Service) GetCurrent(domainName string) (*SnapshotInfo, error) {
	var snapInfo *SnapshotInfo

	err := s.connManager.WithConn(func(conn *libvirt.Connect) error {
		dom, err := conn.LookupDomainByName(domainName)
		if err != nil {
			return fmt.Errorf("domain not found: %w", err)
		}
		defer dom.Free()

		snap, err := dom.SnapshotCurrent(0)
		if err != nil {
			return fmt.Errorf("no current snapshot: %w", err)
		}
		defer snap.Free()

		snapInfo, err = s.getSnapshotInfo(dom, snap, false)
		return err
	})

	return snapInfo, err
}

// getSnapshotInfo 从 libvirt.DomainSnapshot 提取信息
func (s *Service) getSnapshotInfo(dom *libvirt.Domain, snap *libvirt.DomainSnapshot, includeXML bool) (*SnapshotInfo, error) {
	name, err := snap.GetName()
	if err != nil {
		return nil, err
	}

	domainName, err := dom.GetName()
	if err != nil {
		return nil, err
	}

	// 获取快照 XML 以解析更多信息
	xmlDesc, err := snap.GetXMLDesc(0)
	if err != nil {
		return nil, err
	}

	info := &SnapshotInfo{
		Name:   name,
		Domain: domainName,
	}

	// 解析 XML 获取创建时间和描述
	// 这里简化处理，实际应使用 libvirtxml 解析
	info.State = "disk-snapshot"
	info.CreationTime = time.Now() // 应从 XML 解析

	// 检查是否为当前快照
	current, err := dom.SnapshotCurrent(0)
	if err == nil {
		currentName, _ := current.GetName()
		info.IsCurrent = (currentName == name)
		current.Free()
	}

	if includeXML {
		info.XMLConfig = xmlDesc
	}

	return info, nil
}

// buildSnapshotXML 构建快照 XML
func (s *Service) buildSnapshotXML(spec *CreateSpec) string {
	xml := "<domainsnapshot>\n"

	if spec.Name != "" {
		xml += fmt.Sprintf("  <name>%s</name>\n", spec.Name)
	}

	if spec.Description != "" {
		xml += fmt.Sprintf("  <description>%s</description>\n", spec.Description)
	}

	xml += "</domainsnapshot>"
	return xml
}
